#include "center_line.h"

#include <QLineF>
#include <QPointF>
#include <QDebug>

#include "tools/layer_interface.h"
#include "../../layout/layout.hpp"
#include "../../utils/geom_cal_2d.h"
#include "../../utils/kutils.h"
#include "../../undoRedo/undoRedo.hpp"
#include "../../utils/render_ref.h"
#include "../../utils/render_line.h"
#include "../../select/events.hpp"
#include "../../select/select_cmd.hpp"

namespace qbe::centerline {

namespace Internal {
static constexpr double accuracy_error = 1e-4;
}

class CenterLineManager {

 public:
  static CenterLineManager* getInstance();
  ecs::Bus* bus;
  ecs::Query* query;
  entt::registry* ecs_reg;

 public:
  CenterLineManager();

  void setPreselectLine(QLineF line);
  void setSelectLine(QLineF line);

  void handleMouseMove(double x, double y);
  void handleMouseClick(double x, double y);
  // 取消画板高亮选中
  void cancelLayoutHighLight();
  // 清除提示
  void clearMsg();

 private:
  void showSelectFirstLineMsg();
  void showSelectSecondLineMsg();
  void showAreCollinearMsg();

  void initLine();
  void deinitLine();

  // 点是否在线段上
  bool isIntersectOnLine(const QPointF& intersect, const QLineF& line) const;
  // 判断两条线段是否平行
  bool isParallel(const QLineF& line1, const QLineF& line2) const;
  // 判断两条线段是否共线
  bool isCollinear(const QLineF& line1, const QLineF& line2) const;
  // 线段最靠近p点的端点
  QPointF closePoint(const QPointF& p, const QLineF& line) const;
  // 线段最远离p点的端点
  QPointF farPoint(const QPointF& p, const QLineF& line) const;
  // 获取当前预选中的线段
  QLineF getPreselectedLine();
  // 获取当前选中的线段
  QLineF getSelectedLine();
  // 点到线段的垂直距离
  double perpendicularDistance(const QPointF& point, const QLineF& line) const;
  // 绘制预览线
  void drawPreviewCenterLine(const QLineF& line);
  // 绘制等间距线
  void drawIsometricLine(QLineF line1, QLineF line2);
  // 绘制角平分线
  void drawAngleBisector(QLineF line1, QLineF line2, QPointF line1_pos, QPointF line2_pos);

 private:
  // 预选中线段
  QLineF m_preselect_line;
  // 选中线段
  QLineF m_select_line;

  // 第一条线段
  QLineF m_line1;
  // 选择第一条线段时，鼠标点击的点
  QPointF m_line1_pos;
  // 预览线对象
  std::shared_ptr<utils::TempRender::RenderLine> m_temp_line;
  // 预览线数据
  QLineF m_preview_line;
};

CenterLineManager* CenterLineManager::getInstance() {
  static CenterLineManager m;
  return &m;
}

CenterLineManager::CenterLineManager() {

}

void CenterLineManager::setPreselectLine(QLineF line) {
  m_preselect_line = line;
}

void CenterLineManager::setSelectLine(QLineF line) {
  m_select_line = line;
}

void CenterLineManager::handleMouseMove(double x, double y) {
  // 必须选中第一条线段
  if (m_line1.isNull()) {
    showSelectFirstLineMsg();
    return;
  } else {
    showSelectSecondLineMsg();
  }

  QLineF line2 = getPreselectedLine();
  if (line2.isNull()) {
    deinitLine();
    return;
  }

  // 不能选择同一条线
  if (line2 == m_line1) {
    return;
  }

  // 判断线段1和线段2是否共线
  if (isCollinear(m_line1, line2)) {
    deinitLine();
    showAreCollinearMsg();
    return;  // 共线时无法绘制中心线
  }

  // 判断线段1和线段2是否平行
  if (isParallel(m_line1, line2)) {
    // 平行，绘制等间距线
    drawIsometricLine(m_line1, line2);
  } else {
    // 不平行，绘制角平分线
    QPointF line2_pos = {x, y};
    drawAngleBisector(m_line1, line2, m_line1_pos, line2_pos);
  }
}

void CenterLineManager::handleMouseClick(double x, double y) {
  if (m_line1.isNull()) {
    m_line1 = getSelectedLine();
    m_line1_pos = {x, y};
  } else {
    if (!m_temp_line) {
      // 尝试绘制预览线
      handleMouseMove(x, y);
      if (!m_temp_line) {
        // 没有预览线则退出
        return;
      }
    }

    // 共线判断
    QLineF line2 = getSelectedLine();
    if (!isCollinear(m_line1, line2)) {
      // 不共线，则绘制中心线
      auto& cell = query->get_resource<qlib::Cell::s_ptr>();
      auto& options = query->get_resource<vsg::ref_ptr<vsg::Options>>();
      auto& undoredo = query->get_resource<undoRedoT::UndoRedoModule>();
      auto& layout_cmd = query->get_resource<layout::LayoutCmd>();
      auto& layer_interface = query->get_resource<qbe::tools::LayerInterfaceObjcet>();
      auto& select_cmd = query->get_resource<select::SelectCmd>();

      undoredo.start(cell);
      qlib::Path::s_ptr line = qlib::Path::create();
      line->setLayer(static_cast<uint32_t>(layer_interface.getCurrentSelectLayerNumFunc()));
      line->spine.points = { { m_preview_line.p1().x(), m_preview_line.p1().y() },
                             { m_preview_line.p2().x(), m_preview_line.p2().y() } };
      auto e = layout_cmd.add(line);
      undoredo.add(e);
      undoredo.end();

      // 取消画板选中,重置提示信息
      cancelLayoutHighLight();
      showSelectFirstLineMsg();
      select_cmd.clear_all();
    }
    // 清除预览线
    deinitLine();
    m_line1 = QLineF();
  }
}

void CenterLineManager::clearMsg() {
  bus->send<qbe::UiMessage::OperatorInfoMessage>(
      qbe::UiMessage::OperatorInfoMessage {QString(QObject::tr(""))}
      );
}

void CenterLineManager::showSelectFirstLineMsg() {
  bus->send<qbe::UiMessage::OperatorInfoMessage>(
      qbe::UiMessage::OperatorInfoMessage {QString(QObject::tr("Mode: Draw centerline | Select first segment"))}
  );
}

void CenterLineManager::showSelectSecondLineMsg() {
  bus->send<qbe::UiMessage::OperatorInfoMessage>(
      qbe::UiMessage::OperatorInfoMessage {QString(QObject::tr("Mode: Draw centerline | Select second segment"))}
  );
}

void CenterLineManager::showAreCollinearMsg() {
  bus->send<qbe::UiMessage::OperatorInfoMessage>(
      qbe::UiMessage::OperatorInfoMessage {QString(QObject::tr("Mode: Centerline | Line segments coincide"))}
  );
}

void CenterLineManager::initLine() {
  auto options = query->get_resource<vsg::ref_ptr<vsg::Options>>();
  for (auto [e, node] : ecs_reg->view<CenterLineTag, vsg::ref_ptr<vsg::Switch>>().each()) {
    std::shared_ptr<utils::TempRender::RenderLine> render_line =
        std::make_shared<utils::TempRender::RenderLine>(options, std::vector<qlib::Path::s_ptr>{});
    node->addChild(true, render_line->switchObject);
    QColor c("#81fc04");
    render_line->setLayerType(vsg::vec4(c.redF(), c.greenF(), c.blueF(), c.alphaF()), "B2");
    this->m_temp_line = render_line;
  }
}

void CenterLineManager::deinitLine() {
  if (m_temp_line != nullptr) {
     for (auto [e, node] : ecs_reg->view<CenterLineTag, vsg::ref_ptr<vsg::Switch>>().each()) {
       node->clear();
     }
  }
  m_temp_line = nullptr;
  m_preview_line = QLineF();
}

bool CenterLineManager::isIntersectOnLine(const QPointF& intersect, const QLineF& line) const {
  double x_lower = std::min(line.p1().x(), line.p2().x());
  double x_upper = std::max(line.p1().x(), line.p2().x());
  double y_lower = std::min(line.p1().y(), line.p2().y());
  double y_upper = std::max(line.p1().y(), line.p2().y());
  return intersect.x() >= x_lower && intersect.x() <= x_upper && intersect.y() >= y_lower && intersect.y() <= y_upper;
}

bool CenterLineManager::isParallel(const QLineF& line1, const QLineF& line2) const {
  // 获取线段的起点和终点
  QPointF p1 = line1.p1();
  QPointF p2 = line1.p2();
  QPointF p3 = line2.p1();
  QPointF p4 = line2.p2();

  // 计算方向向量
  QPointF dir1 = p2 - p1;
  QPointF dir2 = p4 - p3;

  // 计算叉积
  qreal crossProduct = dir1.x() * dir2.y() - dir1.y() * dir2.x();

  // 如果叉积为零，说明方向向量平行(需要考虑误差)
  return std::abs(crossProduct) < 1e-6;
}

bool CenterLineManager::isCollinear(const QLineF& line1, const QLineF& line2) const {
  if (!isParallel(line1, line2)) {
    return false;
  }

  double distance = perpendicularDistance(line1.p1(), line2);
  bool collinear = distance < Internal::accuracy_error;
  return collinear;
}

double CenterLineManager::perpendicularDistance(const QPointF& point, const QLineF& line) const {
  // 获取线段端点
  QPointF p1 = line.p1();
  QPointF p2 = line.p2();

  // 计算方向向量
  QPointF direction = p2 - p1;

  // 计算点到线段起点的向量
  QPointF toPoint = point - p1;

  // 计算叉积
  double crossProduct = direction.x() * toPoint.y() - direction.y() * toPoint.x();

  // 计算线段长度
  double lineLength = line.length();

  // 如果线段长度为0,返回点到起点的距离
  if (lineLength == 0) {
    return QLineF(point, p1).length();
  }

  // 返回垂直距离
  return std::abs(crossProduct) / lineLength;
}

QPointF CenterLineManager::closePoint(const QPointF& p, const QLineF& line) const {
  return QLineF(p, line.p1()).length() < QLineF(p, line.p2()).length() ? line.p1() : line.p2();
}

QPointF CenterLineManager::farPoint(const QPointF& p, const QLineF& line) const {
  return QLineF(p, line.p1()).length() > QLineF(p, line.p2()).length() ? line.p1() : line.p2();
}

QLineF CenterLineManager::getPreselectedLine() {
  return m_preselect_line;
  // auto& cell_cmd = query->get_resource<layout::CellCmd>();
  // auto current_cell = cell_cmd.cell;
  // auto& reg = current_cell->reg;
  // auto& select_part_model = query->get_resource<select::SelectPartModel>();

  // auto& axis = query->get_resource<axis::Axis>();
  // auto& select_cmd = query->get_resource<select::SelectCmd>();

  // select::SelectCmd::PartMap select_parts;
  // select_cmd.get_part(axis.real_x, axis.real_y, select_parts);

  // if (select_parts.empty()) {
  //   select_cmd.clear_hover_parts();
  //   return QLineF();
  // }

  // qbe::select::SelectPartData data = select_parts.begin()->second;
  // if (data.edge_id_map.empty()) {
  //   select_cmd.clear_hover_parts();
  //   return QLineF();
  // }

  // qlib::Vec2dArray edge = data.get_edge(data.edge_id_map.begin()->first);

  // if (edge.size() != 2) {
  //   select_cmd.clear_hover_parts();
  //   return QLineF();
  // }
  // select::SelectCmd::PartMap hover;
  // hover.insert(*select_parts.begin());
  // select_cmd.add_hover_parts(hover);
  // return QLineF(edge[0].x, edge[0].y,
  //               edge[1].x, edge[1].y);
}

QLineF CenterLineManager::getSelectedLine() {
  return m_select_line;
  // auto& cell_cmd = query->get_resource<layout::CellCmd>();
  // auto current_cell = cell_cmd.cell;
  // auto& reg = current_cell->reg;
  // auto& select_part_model = query->get_resource<select::SelectPartModel>();
  // auto& axis = query->get_resource<axis::Axis>();
  // auto& select_cmd = query->get_resource<select::SelectCmd>();

  // select::SelectCmd::PartMap select_parts;
  // select_cmd.get_part(axis.real_x, axis.real_y, select_parts);

  // if (select_parts.empty()) {
  //   return QLineF();
  // }

  // qbe::select::SelectPartData data = select_parts.begin()->second;
  // if (data.edge_id_map.empty()) {
  //   return QLineF();
  // }

  // qlib::Vec2dArray edge = data.get_edge(data.edge_id_map.begin()->first);

  // if (edge.size() != 2) {
  //   return QLineF();
  // }

  // select::SelectCmd::PartMap select;
  // select.insert(*select_parts.begin());
  // select_cmd.add_select_parts(select);
  // return QLineF(edge[0].x, edge[0].y,
  //               edge[1].x, edge[1].y);
}

void CenterLineManager::drawPreviewCenterLine(const QLineF& l) {
  if (m_temp_line == nullptr) {
    initLine();
  }
  // qDebug() << l;
  qlib::Path::s_ptr _ptr = qlib::Path::create();
  qlib::Vec2d p1 = {l.p1().x(), l.p1().y()};
  qlib::Vec2d p2 = {l.p2().x(), l.p2().y()};
  _ptr->init_spine({p1, p2});
  m_temp_line->updateData({_ptr});
  m_preview_line = l;
}

void CenterLineManager::drawIsometricLine(QLineF line1, QLineF line2) {
  if (line1.p1().x() > line1.p2().x()) {
    line1 = QLineF(line1.p2(), line1.p1());
  }
  if (line2.p1().x() > line2.p2().x()) {
    line2 = QLineF(line2.p2(), line2.p1());
  }
  if (line1.p1().y() > line1.p2().y()) {
    line1 = QLineF(line1.p2(), line1.p1());
  }
  if (line2.p1().y() > line2.p2().y()) {
    line2 = QLineF(line2.p2(), line2.p1());
  }

  // 计算中心线
  QLineF center_line(QLineF(line1.p1(), line2.p1()).center(), QLineF(line1.p2(), line2.p2()).center());
  // 绘制中心线
  drawPreviewCenterLine(center_line);
}

void CenterLineManager::drawAngleBisector(QLineF line1, QLineF line2, QPointF line1_pos, QPointF line2_pos) {
  QLineF center_line;
  if (QLineF(line1.p1(), line2.p1()).length() < Internal::accuracy_error) {
    center_line.setP1(line1.p1());
    center_line.setP2(QLineF(line1.p2(), line2.p2()).center());
  } else if (QLineF(line1.p1(), line2.p2()).length() < Internal::accuracy_error) {
    center_line.setP1(line1.p1());
    center_line.setP2(QLineF(line1.p2(), line2.p1()).center());
  } else if (QLineF(line1.p2(), line2.p1()).length() < Internal::accuracy_error) {
    center_line.setP1(line1.p2());
    center_line.setP2(QLineF(line1.p1(), line2.p2()).center());
  } else if (QLineF(line1.p2(), line2.p2()).length() < Internal::accuracy_error) {
    center_line.setP1(line1.p2());
    center_line.setP2(QLineF(line1.p2(), line2.p1()).center());
  } else {
    // 交点计算
    QPointF intersect;
    QLineF::IntersectionType type = line1.intersects(line2, &intersect);

    // line1最靠近位置line1_pos的端点(方向点）
    QPointF point1;
    if (QLineF(line1.p1(), line1_pos).length() < QLineF(line1.p2(), line1_pos).length()) {
      point1 = line1.p1();
    } else {
      point1 = line1.p2();
    }
    // line2最靠近位置line2_pos的端点(方向点）
    QPointF point2;
    if (QLineF(line2.p1(), line2_pos).length() < QLineF(line2.p2(), line2_pos).length()) {
      point2 = line2.p1();
    } else {
      point2 = line2.p2();
    }

    // 方向点不能是交点，若是交点则需要切换成另外一个端点
    if (point1 == intersect) {
      point1 = (point1 == line1.p1() ? line1.p2() : line1.p1());
    }
    if (point2 == intersect) {
      point2 = (point2 == line2.p1() ? line2.p2() : line2.p1());
    }

    // 方向向量
    QVector2D v1(point1.x() - intersect.x(), point1.y() - intersect.y()),
        v2(point2.x() - intersect.x(), point2.y() - intersect.y());

    // 归一化后求角平分向量
    QVector2D v_bisector = v1.normalized() + v2.normalized();
    v_bisector.normalize();

    // 角平分线段
    QLineF line_bisector(intersect, intersect + v_bisector.toPointF() * 10);

    QPointF p_start, p_end;
    if (type == QLineF::BoundedIntersection) {
      // 交点在两条线段上(线段有实际交点)

      // 求中心线两个端点
      QLineF line3(point1, point2);
      QLineF line4(line1.p1() == point1 ? line1.p2() : line1.p1(),
                   line2.p1() == point2 ? line2.p2() : line2.p1());
      line_bisector.intersects(line3, &p_start);

      if (line4.p1() == line4.p2()) {
        // 同一个点,直接使用该点
        p_end = line4.p1();
      } else {
        // 计算交点
        line_bisector.intersects(line4, &p_end);
      }
    } else if (type == QLineF::UnboundedIntersection) {
      // 交点在线段(至少一条)的延长线上
      bool on_line1 = isIntersectOnLine(intersect, line1);
      bool on_line2 = isIntersectOnLine(intersect, line2);

      if (on_line1) {
        // 交点在线段1上
        QPointF far2 = farPoint(intersect, line2);
        p_start = intersect;
        line_bisector.intersects(QLineF(point1, far2), &p_end);
      } else if (on_line2) {
        // 交点在线段2上
        QPointF far1 = farPoint(intersect, line1);
        p_start = intersect;
        line_bisector.intersects(QLineF(point2, far1), &p_end);
      } else {
        // 交点在延长线上
        QPointF close1 = closePoint(intersect, line1), far1 = farPoint(intersect, line1),
                close2 = closePoint(intersect, line2), far2 = farPoint(intersect, line2);

        QLineF line3(close1, close2), line4(far1, far2);
        line_bisector.intersects(line3, &p_start);
        line_bisector.intersects(line4, &p_end);
      }
    }
    center_line = QLineF(p_start, p_end);
  }
  drawPreviewCenterLine(center_line);
}

void CenterLineManager::cancelLayoutHighLight() {
  auto& select_part_model = query->get_resource<select::SelectPartModel>();
  select_part_model.selects.clear();
  select_part_model.hovers.clear();
  select_part_model.hover.clear();
  auto& select_event_writer = query->get_event_writer<qbe::select::Event>();
  select_event_writer.send(qbe::select::Event{qbe::select::Code::PartSelectCancel});
}

/*--------------------------------------------------------------------------------------------------------------*/

void exit(ecs::Query query, state::AllModeType enter_mode) {
  if (std::get<state::EditingModeType>(enter_mode) == state::EditingModeType::CenterLine) {
    auto& state = query.get_resource<state::State>();
    state.exit();
  } else {
    auto& param = query.get_resource<CenterLineModel>();
    auto& cell_cmd = query.get_resource<layout::CellCmd>();
    auto current_cell = cell_cmd.cell;
    auto& select_model = query.get_resource<select::SelectModel>();
    // auto& model = query.get_resource<CenterLineModel>();
    // model.is_init = false;
    select_model.select_ele_ctrl = 0;
    select_model.is_continuous_select = false;
    // 清除选择标记
    for (auto [e] : current_cell->reg.view<select::SelectTag>().each()) {
      current_cell->reg.remove<select::SelectTag>(e);
    }
    auto& ecs_reg = query.get_reg();
    for (auto [e, node] : ecs_reg.view<CenterLineTag, vsg::ref_ptr<vsg::Switch>>().each()) {
      node->setAllChildren(false);
      node->children.clear();
    }
  }
}

void init(entt::registry& reg, ecs::Commands commands, ecs::Query query) {
  auto& state = query.get_resource<state::State>();

  // 退出逻辑
  state.addExitCall(state::EditingModeType::CenterLine, exit);

  for (auto [e, tran] : reg.view<render::SceneTag, vsg::ref_ptr<vsg::MatrixTransform>>().each()) {
    // 创建 Switch
    auto switchObject = vsg::Switch::create();
    tran->addChild(switchObject);
    commands.spawn(CenterLineTag{}, switchObject);
  }
}

void update(entt::registry& ecs_reg, ecs::Query query, ecs::Bus& bus, ecs::EventWriter<msg::RenderEvent> event) {
  auto& state = query.get_resource<state::State>();

  // 仅在模式执行
  if (state.getEditingMode() != state::EditingModeType::CenterLine) {
    return;
  }

  auto& axis = query.get_resource<axis::Axis>();
  auto& cell_cmd = query.get_resource<layout::CellCmd>();
  auto& hand = query.get_resource<vsg::ref_ptr<input::HandleBundle>>();
  auto& select_cmd = query.get_resource<select::SelectCmd>();

  select::SelectCmd::PartMap select_parts;
  select_cmd.get_part(axis.real_x, axis.real_y, select_parts);

  // 中心线模式需要切换到部分选择模式
  state.switchMode(state::SelectModeType::Part);

  double x = axis.real_x;
  double y = axis.real_y;

  CenterLineManager::getInstance()->bus = &bus;
  CenterLineManager::getInstance()->query = &query;
  CenterLineManager::getInstance()->ecs_reg = &ecs_reg;

  if (hand->keyReleased(vsg::KEY_Escape)) {
    CenterLineManager::getInstance()->clearMsg();
    select_cmd.clear_all();
    state.exit();
    return;
  }

  // 鼠标移动
  if (hand->mouse_move) {
    QLineF line;
    if (select_parts.empty()) {
      select_cmd.clear_hover_parts();
    } else {
      qbe::select::SelectPartData data = select_parts.begin()->second;
      if (data.edge_id_map.empty()) {
        select_cmd.clear_hover_parts();
      } else {
        qlib::Vec2dArray edge = data.get_edge(data.edge_id_map.begin()->first);
        if (edge.size() != 2) {
          select_cmd.clear_hover_parts();
        } else {
          select::SelectCmd::PartMap hover;
          hover.insert(*select_parts.begin());
          select_cmd.add_hover_parts(hover);
          line = QLineF(edge[0].x, edge[0].y,
                        edge[1].x, edge[1].y);
        }
      }
    }

    CenterLineManager::getInstance()->setPreselectLine(line);
    CenterLineManager::getInstance()->handleMouseMove(x, y);
  }

  // 鼠标左键
  if (hand->mouseReleased(1)) {
    QLineF line;
    if (select_parts.empty()) {
      select_cmd.clear_hover_parts();
    } else {
      qbe::select::SelectPartData data = select_parts.begin()->second;
      if (data.edge_id_map.empty()) {
        select_cmd.clear_hover_parts();
      } else {
        qlib::Vec2dArray edge = data.get_edge(data.edge_id_map.begin()->first);
        if (edge.size() != 2) {
          select_cmd.clear_hover_parts();
        } else {
          select::SelectCmd::PartMap select;
          select.insert(*select_parts.begin());
          select_cmd.add_select_parts(select);
          line = QLineF(edge[0].x, edge[0].y,
                        edge[1].x, edge[1].y);
        }
      }
    }
    CenterLineManager::getInstance()->setSelectLine(line);
    CenterLineManager::getInstance()->handleMouseClick(x, y);
  }

}

void post(entt::registry& reg, ecs::Commands commands, ecs::Query query, ecs::Bus& bus) {

}

} // namespace qbe::centerline
